﻿/*
 * DHT Engine
 * 
 * DHT Protocol Engine
 * 
 * See protocol definition:
 * http://www.bittorrent.org/beps/bep_0005.html
 * 
 * Author: snowdreamist
 * Date: 2011/11/22
 * 
 */
using System;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.Text;
using System.Threading;

namespace BitTorrentSharp.DHT
{
    public sealed class DHTEngine
    {
        #region singleton

        private static volatile DHTEngine _instance = null;
        private static readonly object _instanceSyncRoot = new object();
        /// <summary>
        /// Singleton instance
        /// </summary>
        public static DHTEngine Instance
        {
            get
            {
                if (_instance == null)
                    lock (_instanceSyncRoot)
                        if (_instance == null)
                            _instance = new DHTEngine();
                return _instance;
            }
        }

        #endregion
        /// <summary>
        /// Constructor
        /// </summary>
        private DHTEngine()
        {
            this.IsInitialized = false;
        }

        #region initialize
        /// <summary>
        /// is initialized
        /// </summary>
        public bool IsInitialized { get; private set; }
        /// <summary>
        /// initialize
        /// </summary>
        public void Initialize(NodeID currentNodeID, IPEndPoint endPoint, DHTConfigurationSection config)
        {
            if (IsInitialized)
                throw new InvalidOperationException("Has been initialized");
            if (config == null)
                throw new ArgumentNullException("config");

            if (Monitor.TryEnter(this))
            {
                this.Configuration = config;
                // TODO Network
                // node
                this.NodeFactory = new NodeFactory(this);
                // routing table
                this.RoutingTable = new RoutingTable(this, this.NodeFactory.CreateNode(currentNodeID, endPoint));
                // bucket refresh timer
                this._bucketRefreshTimer = new Timer(
                    this.BucketRefreshCallback,
                    null,
                    this.Configuration.Routing.Bucket.RefreshInterval,
                    this.Configuration.Routing.Bucket.RefreshInterval
                    );

                this.IsInitialized = true;
            }
            else
            {
                throw new InvalidOperationException("Another initialize action is executing");
            }
        }
        #endregion

        #region config
        /// <summary>
        /// config
        /// </summary>
        public DHTConfigurationSection Configuration { get; private set; }

        #endregion

        #region private

        #region Refresh
        /// <summary>
        /// refresh timer
        /// </summary>
        private Timer _bucketRefreshTimer;
        /// <summary>
        /// bucket refresh call back
        /// </summary>
        /// <param name="state"></param>
        private void BucketRefreshCallback(object state)
        {
            try
            {
                this.RoutingTable.Refresh();
            }
            catch (Exception error)
            {
                System.Diagnostics.Debug.WriteLine(string.Format("BucketRefreshCallback failed. Error:\n\t{0}", error), "DHTEngine");
            }
        }

        #endregion

        #endregion

        /// <summary>
        /// Node factory
        /// </summary>
        internal NodeFactory NodeFactory { get; private set; }
        /// <summary>
        /// Routing table
        /// </summary>
        public RoutingTable RoutingTable { get; private set; }
    }
}
